'''
1、鼠标操作：
         常见的操作：
                  点击、右击、双击、悬停、拖拽
         实例化鼠标对象（关联浏览器对象）：                                 在 selenium 中，将操作鼠标的方法封装在 ActionChains 类中
                                    action = ActionChains(driver)
         方法：
             context_click(element)            右击 -> 模拟鼠标右击效果
             double_click(element)             双击 -> 模拟鼠标双击效果
             drag_and_drop(source, target)     拖动 -> 模拟鼠标拖动效果
             move_to_element(element)          悬停 -> 模拟鼠标悬停效果             （该方法执行时，不要动鼠标）
             perform()                         执行 -> 从方法用来执行以上所有鼠标操作  （必须调用，否则上述操作无效）
2、键盘操作：
         导包：
             from selenium.webdriver.common.keys import Keys
         常见的操作：
                  send_keys(Keys.BACK_SPACE)     删除键         等价于BACKSPACE
                  send_keys(Keys.SPACE)          空格键
                  send_keys(Keys.TAB)            制表键
                  send_keys(Keys.ESCAPE)         回退键
                  send_keys(Keys.ENTER)          回车键
                  send_keys(Keys.CONTROL, 'a')   全选（ctrl + A）     MacOS系统，将 CONTROL 更换成 COMMAND
                  send_keys(Keys.CONTROL, 'c')   复制（ctrl + C）
                  send_keys(Keys.CONTROL, 'v')   粘贴（ctrl + V）     复制之后，可以在任意位置粘贴，是由系统的剪切板实现的
3、html特殊元素：
      ① 元素等待：
               概念：在定位页面元素时如果未找到，会在指定时间内一直等待的过程
               为什么设置：
                        网络速度慢
                        电脑配置低
                        服务器处理请求慢
               类型：
                   11、隐式等待：
                             概念：定位元素时，如果能定位到元素则直接返回该元素，不触发等待。
                                  如果不能定位到该元素，则间隔一段时间（不可控制）后再去定位元素。
                                  如果在达到最大时长时还没有找到指定元素，则抛出元素不存在的异常：NoSuchElementException
                             实现方式：
                                    driver.implicitly_wait(等待最大时长)     单位：秒
                             说明：隐式等待为全局有效，只需要设置一次，就会作用于所有元素（写代码时，先写最大化窗口，再写隐式等待，一般设置为30秒）
                                  当隐式等待被激活时，虽然目标元素已出现，但还是会因为页面其他元素未加载完成，而继续等待，进而增加代码的执行时长
                   12、显示等待：
                             概念：定位元素时，如果能定位到元素则直接返回该元素，不触发等待。
                                  如果不能定位到该元素，则间隔一段时间（可控制）后再去定位元素。
                                  如果在达到最大时长时还没有找到指定元素，则抛出元素不存在的异常：TimeoutException
                             实现方式：
                                    from selenium.webdriver.support.wait import WebDriverWait
                                    WebDriverWait(driver, timeout, poll_frequency=0.5)         (poll_frequency检测间隔时间，默认0.5）
                                    调用方法：util(method)                                       （method，用来实现对元素的定位，一般使用匿名函数）
                                    element = WebDriverWait(driver, 10, 1).util(lambda x: x.find_element(By.ID, "user))
                             说明：元素操作代码没有提示，需要手动编辑，可以提前写好再复制粘贴到指定位置
                   13、对比：
                                                  元素个数       调用方式            异常类型
                           隐式等待                  全局          浏览器对象调用       NoSuchElementException
                           显示等待                  单个          实例化对象调用       TimeoutException
                           扩展：强制等待(sleep)      全局          方法                NoSuchElementException
      ② 下拉框：
              概念：
                   下拉框就是 html 中的 <select> 元素
              传统方法：
                     driver.find_element(By.CSS_SELECTOR, '[value="gz"]').click()
              select类：
                       操作方法：
                              select_by_index(index)              根据option索引来定位，从0开始
                              select_by_value(value)              根据option属性 value值来定位
                              select_by_visible_text(text)        根据option显示文本来定位
                       实现步骤：
                              from selenium.webdriver.support.select import Select
                              select = Select(driver.find_element(By.ID, "addr"))
                              select.select_by_index(2)
                              select.select_by_value("sh")
                              select.select_by_visible_text("深圳")
                       注意：
                           如果页面内需要操作的下拉框元素有多个，需要根据目标下拉框，依次实例化下拉框选择对象
                           根据具体需求，三种下拉框内容元素选择方法，任选其一使用即可
                           调用的方法如果存在黑线，表示该方法已经过期，将来会被移除，不建议使用
      ③ 弹出框：
              应用场景：
                      页面操作过程中，一旦出现弹窗，不进行处理，会导致后续操作无法执行
              分类：
                  系统弹窗（JS 实现）：
                                   说明：无法通过鼠标右键检查选项获取元素信息
                                   分类：
                                       alert      警告框
                                       confirm    确认框
                                       prompt     提示框
                  自定义弹窗（前端代码封装）:
                                        说明：自定义弹窗可以通过鼠标右键的检查选项获取元素信息
                                             出现自定义弹窗时，直接定未目标元素并操作，移除弹窗即可
              处理方法：
                     alert = driver.switch_to.alert                                （三种弹出框都使用 alert）
                     alert.text            返回 alert/confirm/prompt 中的文字信息
                     alert.accept()        接受对话框选项
                     alert.dismiss()       取消对话框选项
      ④ 滚动条：
              说明：一种可控制页面显示范围的组件
                   Selenium 框架中没有专门处理滚动条的方法，需要调用 js 代码来实现操作
              应用场景：
                     在html页面中，由于前端技术框架的原因，页面元素为动态显示，元素根据滚动条的下拉而被加载
                     页面注册同意条款，需滚动条到最底层，才能点击同意
              实现方式：
                     js = "window.scrollTo(0, 1000)"     0-左边距   1000-上边距（单位：像素）       回到原点：设置成（0，0）
                     driver.execute_script(js)
      ⑤ frame：
              说明：html页面中的一种框架，主要作用是在当前页面中指定区域显示另一页面元素
              形式：
                  11、
                      <frameset rows="50%, 50%">
                            <frame src="注册A.html" name="register_a" id="frame1" scrolling="auto">
                            <frameset cols="50%, 50%">
                                <frame src="注册B.html" name="register_b" id="frame2" scrolling="auto">
                                <frame src="注册C.html" name="register_c" id="frame3" scrolling="auto">
                            </frameset>
                      </frameset>
                  12、
                      <iframe name="frame" src="注册.html" width="200" height="200"></iframe>
              切换方法：
                     driver.switch_to.frame('frame1')           (frame1：可以为frame框架的name、id或者定位到的frame元素，确保是唯一值)
                     driver.switch_to.default_content()         (在frame中操作其他页面，必须先恢复默认页面，才能进一步操作)
      ⑥ 多窗口：
              说明：在html页面中，当点击超链接或按钮时，有的会在新的窗口打开页面
                   在selenium中，封装了获取当前窗口、所有窗口、指定窗口句柄的方法    （句柄：handle，窗口的唯一识别码）
              切换方法：
                     driver.current_window_handle           获取当前窗口句柄
                     driver.window_handles                  获取所有窗口句柄
                     driver.switch_to.window(handle)        切换到指定句柄窗口  (-1：始终是最新窗口的句柄值）
              切换窗口操作：
                         11、获取所有窗口句柄      handles= driver.window_handles
                         12、切换窗口            driver.switch_to.window(handles[-1])
      ⑦ 窗口截图：
                说明：把当前操作的页面，截图保存到指定位置
                     自动化脚本是由程序执行，有时候打印的错误信息不太明确
                     执行出错时，保存当前窗口截图，可以通过图片直观了解出错的原因
                方法：
                     driver.get_screenshot_as_file(图片保存路径)      (图片路径：./截图.png，建议使用png格式)
                            注意：./image/截图.png，需要先手动创建image文件夹(new - directory)
                扩展：
                    使用时间戳防止文件重名被覆盖:
                                            now_time = strftime('%Y%m%d_%H%M%S')
                                            driver.get_screenshot_as_file('./截图.png_{}'.format(now_time))
                    给元素截图：
                             btn = driver.find_element(By.XPATH, '//*[@value="注册"]')
                             btn.screenshot('./注册按钮.png')
      ⑧ 验证码：
              说明：
                  一种随机生成的信息（数字、字母、汉字、图片、算术题）等，为了防止恶意的请求行为，增加应用的安全性
                  在web应用中，大部分系统在用户登录注册时都需输入验证码，设计自动化测试脚本时，需面两处理验证码的问题
              注意：在自动化测试过程中，必须先处理验证码，否则无法继续执行后续测试
              处理方式：
                     去掉验证码（常用）    - 测试环境下，采用                                                 （开发完成，不做讲解）
                     设置万能验证码（常用） - 生产环境和测试环境下，采用，必须注意保密，不要外泄万能验证码             （开发完成，不做讲解）
                     验证码识别技术        - 通过python-tesseract来识别图片类型验证码：识别率很难达100%          （成功率低，验证码种类繁多，不太适合）
                     记录cookie          - 通过记录cookie进行跳过登录，不能对登录本身功能进行测试时使用           （比较实用）
              cookie：
                     说明：
                         是由web服务器生成的，并保存在用户浏览器上的小文本文件，可包含用户相关信息
                         数据格式：键值对组成
                         产生：客户端请求服务器，如果服务器需要记录该用户状态，就向客户端浏览器颁发一个cookie数据
                         使用：当浏览器再次请求该网站时，浏览器把请求的数据和cookie数据一同提交给服务器，服务器检查该cookie，来辨认用户状态
                         绕过原理：客户端登录账号后，将登录状态相关的cookie信息发送给服务器保存，再发送请求，携带的cookie信息如果和服务器保持一致，则服务器判断客户端为登录状态
                     应用场景：
                            实现会话跟踪，记录用户登录状态
                            实现记住密码和自动登录的功能
                            用户未登录的状态下，记录购物车中的商品
                     方法：
                         print(get_cookie('BDUSS'))        获取指定cookie
                         print(get_cookies())              获取本网站所有本地cookie
                         add_cookies(组装后的键值对)          添加cookie
'''